package com.mjk.common.tools.xml.conver.impl;

import com.mjk.common.tools.logger.BizLogger;
import com.mjk.common.util.ClassUtil;
import com.mjk.common.util.StrUtils;
import com.thoughtworks.xstream.annotations.XStreamAlias;
import com.thoughtworks.xstream.converters.Converter;
import com.thoughtworks.xstream.converters.MarshallingContext;
import com.thoughtworks.xstream.converters.UnmarshallingContext;
import com.thoughtworks.xstream.io.HierarchicalStreamReader;
import com.thoughtworks.xstream.io.HierarchicalStreamWriter;
import org.springframework.util.CollectionUtils;

import java.lang.reflect.Method;
import java.util.Collections;
import java.util.List;
import java.util.Map;

public class BeeNullConverter implements Converter {
    private Map<Class<?>, List<String>> attributes = null;

    @Override
    public void marshal(Object source, HierarchicalStreamWriter writer, MarshallingContext context) {
        if (null == source)
            return;
        Class cType = source.getClass();
        Method[] methods = cType.getMethods();
        writerAttribute(source, writer);
        for (Method m : methods) {
            String methodName = m.getName();
            if (methodName.indexOf("get") != -1 && !methodName.equals("getClass")) {
                if (source instanceof List) {
                    if (!CollectionUtils.isEmpty(((List<?>) source))) {
                        // 获取类上的注解
                        XStreamAlias aliasAnnotation = ((List<?>) source).get(0).getClass().getAnnotation(XStreamAlias.class);
                        String aliasValue = null;
                        if (aliasAnnotation != null) {
                            aliasValue = aliasAnnotation.value();
                        }
                        for (int i = 0; i < ((List<?>) source).size(); i++) {
                            Object obj = ((List<?>) source).get(i);
                            String name = obj.getClass().toString();
                            name = name.substring(name.lastIndexOf(".") + 1);
                            // 如果存在别名注解，则使用别名值
                            if (aliasValue != null && !aliasValue.isEmpty()) {
                                name = aliasValue;
                            }
                            if (i != 0) {
                                writer.startNode(name);
                            }
                            marshal(obj, writer, context);
                            if (i != ((List<?>) source).size() - 1) {
                                writer.endNode();
                            }
                        }
                    }

                } else {
                    boolean isBaseType = ClassUtil.isBasicType((m.getReturnType()));
                    String name = methodName.substring(3);
                    if (isBaseType) {
//                        name = name.toLowerCase();
                    }
                    Object o = null;
                    try {
                        o = m.invoke(source, null);
                    } catch (Exception e) {
                        BizLogger.error(e);
                    }
                    //如果是基本类型调用toString，否则递归
                    if (isBaseType) {
                        if (!isClassAttribute(cType, name)) {
                            writer.startNode(name);
                            writer.setValue(o == null ? "" : o.toString());
                            writer.endNode();
                        }
                    } else {
                        // 获取类上的注解
                        XStreamAlias aliasAnnotation = o.getClass().getAnnotation(XStreamAlias.class);
                        String aliasValue = null;
                        if (aliasAnnotation != null) {
                            aliasValue = aliasAnnotation.value();
                        }
                        // 如果存在别名注解，则使用别名值
                        if (aliasValue != null && !aliasValue.isEmpty()) {
                            name = aliasValue;
                        }
                        writer.startNode(name);
                        marshal(o, writer, context);
                        writer.endNode();
                    }
                }
            }
        }
    }

    @Override
    public Object unmarshal(HierarchicalStreamReader hierarchicalStreamReader, UnmarshallingContext
            unmarshallingContext) {
        return null;
    }

    @Override
    public boolean canConvert(Class aClass) {
        return true;
    }

    /**
     * 获取注册的属性
     *
     * @param type
     * @return
     */
    private List<String> getAttributes(Class<?> type) {
        if (null != attributes) {
            return attributes.get(type);
        }
        return Collections.emptyList();
    }

    /**
     * 输出对象的属性标签
     *
     * @param source
     * @param writer
     */
    private void writerAttribute(Object source, HierarchicalStreamWriter writer) {
        Class cType = source.getClass();
        List<String> value = getAttributes(cType);
        if (!CollectionUtils.isEmpty(value)) {
            Method[] methods = cType.getMethods();
            for (Method method : methods) {
                String methodName = method.getName();
                if (methodName.indexOf("get") != -1 && !methodName.equals("getClass")) {
                    String name = methodName.substring(3);
//                      name = name.toLowerCase();
                    if (value.contains(name)) {
                        Object o = null;
                        try {
                            o = method.invoke(source, null);
                        } catch (Exception e) {
                            BizLogger.error(e);
                        }
                        writer.addAttribute(name, o == null ? "" : o.toString());
                    }
                }
            }
        }
    }

    /**
     * 是否是属性（是属性的不用以单独标签实现）
     *
     * @param type
     * @param attribute
     * @return
     */
    private boolean isClassAttribute(Class<?> type, String attribute) {
        List<String> value = getAttributes(type);
        if (null == value)
            return false;
        return value.contains(attribute);
    }
}
